/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ru.ssau.model;

import ru.ssau.model.storing.factories.ForumDatabaseDAOFactory;
import ru.ssau.model.storing.factories.ForumDAOFactory;
import ru.ssau.model.storing.DataAccessException;
import ru.ssau.model.storing.ForumMapDAO;
import ru.ssau.model.storing.ForumDataAccessObject;
import java.io.Serializable;
import java.util.*;
import org.jdom.Element;
import ru.ssau.entities.Message;
import ru.ssau.entities.User;
import static ru.ssau.model.DataModelChangeEvent.*;

public class DataModel implements Serializable {

    public static final int USERS = 4;
    public static final int MESSAGES = 2;
    public static final int THREADS = 1;
    transient private List<DataModelChangeListener> listeners;
       
    private ForumDataAccessObject store = new ForumMapDAO();
    //isLocked == true, если какой-дибо клиент изменяет модель
    private boolean isLocked;

    public DataModel() {
        ForumDAOFactory daoFactory = new ForumDatabaseDAOFactory();

        store = daoFactory.getDAO();
    }

    //General section
    public Element toXMLElement() {
        return store.toXMLElement();
    }
    /*
    public void loadFromXMLElement(Element data) {
        Element temp = null;
        if ((temp = data.getChild("lastUserId")) != null) {
            lastUserId = Integer.valueOf(temp.getValue());
        }
        if ((temp = data.getChild("lastThreadId")) != null) {
            lastThreadId = Integer.valueOf(temp.getValue());
        }
        if ((temp = data.getChild("lastThreadId")) != null) {
            lastThreadId = Integer.valueOf(temp.getValue());
        }
        List<Element> maps = data.getChildren("Map");
        XMLHelper xhelp = new XMLHelper();
        for (Iterator iterator = maps.iterator(); iterator.hasNext();) {
            Element map = (Element) iterator.next();
            String mapName = map.getAttribute("name").getValue();
            if (mapName.equals("Users")) {
                HashMap<Integer, User> usersMap = xhelp.loadHashMap(map, "User");
                setUsers(usersMap);
            } else if(mapName.equals("Messages")) {
                HashMap<Integer, Message> msgMap = xhelp.loadHashMap(map, "Message");
                setMessages(msgMap);
            } else if(mapName.equals("Threads")) {
                HashMap<Integer, Thread> threadsMap = xhelp.loadHashMap(map, "Thread");
                setThreads(threadsMap);
            }
        }
    }

    public Element toXMLElement() {
        Element root = new Element("DataModel");
        XMLHelper xhelp = new XMLHelper();
        xhelp.addElement(root, new Attribute("name", "Users"), users);
        xhelp.addElement(root, new Attribute("name", "Messages"), messages);
        xhelp.addElement(root, new Attribute("name", "Threads"), threads);
        xhelp.addElement(root, "lastUserId", lastUserId);
        xhelp.addElement(root, "lastThreadId", lastThreadId);
        xhelp.addElement(root, "lastMessageId", lastMessageId);
        return root;
    }*/

    /**
     * Попытка заблокировать модель.
     * @return <code>true</code> - если вызывающему процессу удалось
     * заблокировать моедль для изменения;
     * <code>false</code> - если модель уже заблокирована другим процессом
     */
    public synchronized boolean tryLock() {
        if (!isLocked) {
            isLocked = true;
            return true;
        } else {
            return false;
        }
    }

    public synchronized void unlock() {
        isLocked = false;
    }

    private void firePropertyChange(int entityType, int action, int id) {
        for (DataModelChangeListener l : listeners) {
            l.modelChanged(new DataModelChangeEvent(entityType, action, id));
        }
    }

    public void addDataModelChangeListener(DataModelChangeListener listener) {
        if (listeners == null) {
            listeners = new ArrayList<DataModelChangeListener>(3);
        }
        listeners.add(listener);
    }

    public void removeDataModelChangeListener(DataModelChangeListener listener) {
        listeners.remove(listener);
    }

    public void removeAllDataModelChangeListeners() {
        listeners.clear();
    }

    public Collection<DataModelChangeListener> getDataModelChangeListemers() {
        return listeners;
    }

    public void closeStore() throws DataAccessException {
        store.closeStore();
    }

    //Thread section
    public void addThread(ru.ssau.entities.Thread thread) throws DataAccessException {
        store.addThread(thread);
        firePropertyChange(THREADS, ADD, thread.getId());
    }

    public void replaceThread(ru.ssau.entities.Thread thread) throws DataAccessException {
        store.replaceThread(thread);
        firePropertyChange(THREAD, REPLACE, thread.getId());
    }

    public void deleteThreadById(Integer id) throws DataAccessException {
        store.deleteThreadById(id);
        firePropertyChange(THREAD, DELETE, id);
    }

    public Collection<ru.ssau.entities.Thread> getThreads() throws DataAccessException {
        return store.getThreads();
    }
/*
    public void setThreads(HashMap<Integer, Thread> map) {
        threads = map;
    }*/

    public ru.ssau.entities.Thread getThreadById(Integer id) throws DataAccessException {
        return store.getThreadById(id);
    }

    //Message section
    public void addMessage(Message message) throws DataAccessException {
        store.addMessage(message);
        firePropertyChange(MESSAGE, ADD, message.getId());
    }

    public void replaceMessage(Message message) throws DataAccessException {
        store.replaceMessage(message);
        firePropertyChange(MESSAGE, REPLACE, message.getId());
    }

    public void deleteMessageById(Integer id) throws DataAccessException {
        store.deleteMessageById(id);
        firePropertyChange(MESSAGES, DELETE, id);
    }

    public Collection<Message> getMessages() throws DataAccessException {
        return store.getMessages();
    }

   /* public void setMessages(HashMap<Integer, Message> map) {
        messages = map;
    }*/

    public Message getMessageById(Integer id) throws DataAccessException {
        return store.getMessageById(id);
    }

    //Users section
    public void addUser(User user) throws DataAccessException {
        store.addUser(user);
        firePropertyChange(USERS, ADD, user.getId());
    }

    public void replaceUser(User user) throws DataAccessException {
        store.replaceUser(user);
        firePropertyChange(USER, REPLACE, user.getId());
    }

    public void deleteUserById(Integer id) throws DataAccessException {
        store.deleteUserById(id);
        firePropertyChange(USERS, DELETE, id);
    }

    public Collection<User> getUsers() throws DataAccessException {
        return store.getUsers();
    }

    /*public void setUsers(HashMap<Integer, User> map) {
        users = map;
    }*/

    public User getUserById(Integer id) throws DataAccessException {
        return store.getUserById(id);
    }

}
